﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Xml;
using Moonlite.ExtensionApi.XimlInterfaces;

namespace Moonlite.Platform.Ximl {
    public class XimlTree : IXimlTree {
        private static IXimlTree instance;
        private Assembly currentAssembly;
        private MenuService menuService;
        private ObjectManager objectManager;
        private Dictionary<string, object> resources = new Dictionary<string, object>();
        private Dictionary<string, DescriptorBase> descriptors = new Dictionary<string, DescriptorBase>(); 
        private Dictionary<string, INodeDataProvider> dataProviders = new Dictionary<string, INodeDataProvider>();
        public static IXimlTree Instance {
            get { return instance; }
            private set { instance = value; }
        }
        public Dictionary<string, INodeDataProvider> DataProviders {
            get { return dataProviders; }
        }
        public Dictionary<string, object> Resources {
            get { return resources; }
        }
        public Dictionary<string, DescriptorBase> Descriptors {
            get { return descriptors; }
        }
        public Assembly CurrentAssembly {
            get { return currentAssembly; }
        }
        public IMenuService MenuService {
            get { return menuService; }
        }
        public IObjectManager ObjectManager {
            get { return objectManager; }
        }
        public void BuildItem(string text) {
            BuildItem(text, false);
        }
        public void BuildItem(string text, bool keepInCache) {
            if (currentAssembly == null) {
                throw new NoAssemblyContextException("In order to use BuildItem(string, bool), the assembly currently being parsed must not be null. (Must be in a BuildItem context)");
            }
            BuildItem(text, keepInCache, currentAssembly);
        }
        public void BuildItem(string text, Assembly assembly) {
            BuildItem(text, false, assembly);
        }
        public void BuildItem(string text, bool keepInCache, Assembly assembly) {
            currentAssembly = assembly;
            XmlDocument document = new XmlDocument();
            document.LoadXml(text);
            foreach (XmlNode node in document.ChildNodes) {
                if (node.Name == "Markup") {
                    XimlNode markupRootNode = new XimlNode(node, null);
                    BuildItemCore(node, markupRootNode);
                }
            }
            foreach (DescriptorBase descriptor in descriptors.Values) {
                ObjectManager.CreateObject(descriptor, currentAssembly, descriptor.TargetObjectType);
            }
            if (!keepInCache) {
                Reset();
                currentAssembly = null;
            }
        }
        private void BuildItemCore(XmlNode node, IXimlNode parent) {
            foreach (XmlNode childNode in node.ChildNodes) {
                IXimlNode ximlNode = new XimlNode(childNode, parent);
                foreach (string key in dataProviders.Keys) {
                    if (key == childNode.Name) {
                        DescriptorBase descriptor = null;
                        if (dataProviders[key].ParseXimlNode(ref ximlNode, out descriptor)) {
                            ximlNode.Tag = descriptor;
                            BuildItemCore(childNode, ximlNode);
                        }
                    }
                }
            }
        }
        public DescriptorBase GetDescriptorFromGuid(string guid) {
            foreach (string descriptorGuid in descriptors.Keys) {
                if (descriptorGuid == guid) {
                    return descriptors[descriptorGuid];
                }
            }
            return null;
        }
        public bool IsNativeElement(string guid) {
            guid = guid.ToLower();
            if (guid == NativeElementGuids.BuildButtonGuid.ToLower() ||
                guid == NativeElementGuids.DefaultBarGuid.ToLower() ||
                guid == NativeElementGuids.EditButtonGuid.ToLower() ||
                guid == NativeElementGuids.FileButtonGuid.ToLower() ||
                guid == NativeElementGuids.HelpButtonGuid.ToLower() ||
                guid == NativeElementGuids.MainMenuBarGuid.ToLower() ||
                guid == NativeElementGuids.ProjectButtonGuid.ToLower() ||
                guid == NativeElementGuids.StatusBarGuid.ToLower() ||
                guid == NativeElementGuids.TextEditorBarGuid.ToLower() ||
                guid == NativeElementGuids.ToolsButtonGuid.ToLower() ||
                guid == NativeElementGuids.ViewButtonGuid.ToLower()) {
                return true;
            }
            return false;
        }
        private void ResetDataProviders() {
            dataProviders.Clear();
            dataProviders.Add("Include", new IncludeNodeDataProvider());
            dataProviders.Add("String", new StringNodeDataProvider());
            dataProviders.Add("Image", new IconNodeDataProvider());
            dataProviders.Add("Bar", new BarNodeDataProvider());
            dataProviders.Add("BarItem", new BarItemNodeDataProvider());
            dataProviders.Add("Menu", new ContextMenuNodeDataProvider());
        }
        private void ResetResources() {
            resources.Clear();
        }
        private void ResetDescriptors() {
            descriptors.Clear();
        }
        public void Reset() {
            ResetDataProviders();
            ResetResources();
            ResetDescriptors();
        }
        private XimlTree() {
            Reset();
            menuService = new MenuService();
            objectManager = new ObjectManager();
        }
        static XimlTree() {
            XimlTree.Instance = new XimlTree();
        }
    }
}
